package com.xxx.nio.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;

public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        new EchoServer(8080).start();
    }

    public void start() throws Exception {
        // 事件处理线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();  // boss：监听线程组，负责处理连接，本质是1个线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();   // worker：工作线程组，负责处理数据读写，本质是1个线程池（默认大小为 CPU核数 * 2）
        try {
            // ServerBootstrap：启动Netty服务端
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)     // 配置监听线程组和工作线程组
             .channel(NioServerSocketChannel.class)     // 指定服务端的Channel类型，NioServerSocketChannel为非阻塞IO模型
             .localAddress(new InetSocketAddress(port))     // 绑定本机地址和端口
             .childHandler(new ChannelInitializer<SocketChannel>() {    // 给worker线程组添加业务处理handler
                 @Override
                 public void initChannel(SocketChannel ch) {  // 初始化Channel
                     // 在这里添加具体的handler（可以添加多个handler）
//                     ch.pipeline().addLast(new StringDecoder());    // 将 ByteBuf 转换为字符串，如果在这里进行了处理，那么在自定义handler里就不需要再进行ByteBuf转换了
                     ch.pipeline().addLast(new EchoServerHandler());  // 添加自定义业务处理handler到ChannelPipeline
                 }
             });

            // 异步地绑定服务器;调用sync方法阻塞等待直到绑定完成
            ChannelFuture f = b.bind().sync();
            System.out.println("netty server 在端口：" + port + "上开始监听。。。");
            // 获取Channel的CloseFuture，并且阻塞当前线程直到它完成
            f.channel().closeFuture().sync();
        } finally {
            // 优雅地关闭EventLoopGroup，释放所有的资源
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
